/**
 *  功能：axios 封装
 *  请求拦截， 响应拦截
 */

import axios, {AxiosInstance} from "axios";
//封装的一个toast的文件 用到了element-plus（注意安装 配置，也可以用vant 用哪个组件库都行） 代码会放在下面
import {toast} from "@/utils/commom/ticps.ts";
//基础地址文件代码会放在下面
import {getApiUrl} from "@/utils/commom/string.ts";

class HttpRequest {
//axios的数据类型 AxiosInstance
    static axiosInstance: AxiosInstance;

    static init() {
        //创建axios实例
        this.axiosInstance = axios.create();
        // 设置请求超时
        this.axiosInstance.defaults.timeout = 100000;
        // 表示跨域请求时是否需要使用凭证
        // this.axiosInstance.defaults.withCredentials = true

        // 环境的切换，`baseURL` 将自动加在 `url` 前面，除非 `url` 是一个绝对 URL
        //不同的环境下的基础地址可能会不同，逻辑在基础地址文件中
        //process.env.NODE_ENV 所处的环境 是开发 测试之类的，获取不同的baseURL
        this.axiosInstance.defaults.baseURL = getApiUrl(process.env.NODE_ENV);
        // 设置 post 请求头    application/x-www-form-urlencoded;application/json
        // this.axiosInstance.defaults.headers.common["Authorization"] =
        //   ticketStore.fullToken;（获取token之类的写在了index.ts文件里）
        this.axiosInstance.defaults.headers.post["Content-Type"] =
            "application/json;charset=UTF-8;";


        // 初始化拦截器
        this.initInterceptors();
        return this.axiosInstance;
    }

    static initInterceptors() {
        // 添加请求拦截器
        this.axiosInstance.interceptors.request.use(
            (config) => {

                // 在发送请求之前做些什么

                /* 登录流程控制中，根据本地是否存在 token 判断用户的登录情况
                        但是即使 token 存在，也有可能 token 是过期的，所以在每次的请求头中携带 token
                        后台根据携带的 token 判断用户的登录情况，并返回给我们对应的状态码
                        而后我们可以在响应拦截器中，根据状态码进行一些统一的操作 */
                // webStorage.ls.get('token') && (config.headers.Authorization = `Bearer ${webStorage.ls.get('token')}`);
                // config.headers = config.headers || {};
                // if (localStorage.getItem("token")) {
                //     config.headers.token = localStorage.getItem("token") || "";
                // }

                return config;
            },
            (error) => {
                // 对请求错误做些什么
                return Promise.reject(error);
            }
        );
        // 添加响应拦截器
        this.axiosInstance.interceptors.response.use(
            (response) => {
                // 对响应数据做点什么
                // 如果返回的状态码为200，说明接口请求成功，可以正常拿到数据，否则的话抛出错误
                if (response.status === 200) {
                    //这里.data，请求数据的时候就不用.data了
                    return Promise.resolve(response.data);
                } else {
                    return Promise.reject(response);
                }
                // return response;
            },
            (error) => {
                // 服务器状态码不是 200 的情况
                // 对响应错误做点什么

                const {config, code, request, response, isAxiosError, toJSON} = error;
                if (response) {
                    // 请求已发出，但是不在2xx的范围 调用错误处理的方法（把状态码，错误的提示信息传进去）
                    this.errorHandle(response.status, response.data.message);
                    return Promise.reject(response);
                } else {
                    // 超时提示
                    if (error.message.includes("timeout")) {
                        toast("请求超时，请稍后重试", "fail");
                        return Promise.reject(error);
                    }

                    /* 处理断网的情况
                              eg: 请求超时或断网时，更新 state 的 network 状态
                              network 状态在 app.vue 中控制着一个全局的断网提示组件的显示隐藏
                              关于断网组件中的刷新重新获取数据，会在断网组件中说明 */
                    if (!window.navigator.onLine) {
                        // 如果断网....
                        // store.commit('changeNetwork', false);
                    } else {
                        return Promise.reject(error);
                    }
                }
            }
        );
    }

    /**
     * 请求失败后的错误统一处理
     * @param {Number} status 请求失败的状态码
     * 1**  信息，服务器收到请求，需要请求者继续执行操作
     * 2**  成功，操作被成功接收并处理
     * 3**  重定向，需要进一步的操作以完成请求
     * 4**  客户端错误，请求包含语法错误或无法完成请求
     * 5**  服务器错误，服务器在处理请求的过程中发生了错误
     */
    static errorHandle(status: number, other: string) {
        // 状态码判断
        switch (status) {
            // 400: 请求错误
            case 400:
                toast("请求错误", "fail");
                break;
            // 401: 未登录状态，跳转登录页
            case 401:
                toast("登陆状态已过期，请重新登录", "fail");
                // window.location.href = process.env.VUE_APP_YFTXGLPT
                break;
            // 403 权限不足，拒绝访问
            case 403:
                toast("权限不足，拒绝访问", "fail");
                break;
            // 404请求不存在
            case 404:
                toast("请求的资源不存在或请求地址出错", "fail");
                break;
            // 服务器错误
            case 500:
                toast("服务器错误", "fail");
                break;
            // token异常
            case 10001:
                toast("token异常，请联系管理员", "fail");
                break;
            default:

        }
    }
}

export default HttpRequest.init();